package com.xiaoma.lib.store

import android.content.Context
import org.jetbrains.annotations.NotNull

/**
 * author: liangjingbo
 * date: 2022/6/17
 * describe:
 */
object TPUtils {
    private const val DEFAULT_GROUP_NAME = "xiaoma"
    private val cacheNamedTps = HashMap<String, NamedTP>()
    private var mSpecificNamedTp: NamedTP? = null


    /**
     * 静态方法使用的单例adapter
     */
    private var adapter: IStore? = null

    // 静态方法,使用默认分组名

    /**
     * 基础类型的保存
     *
     * @param context context
     * @param key     key
     * @param value   value
     * @return is operation success
     */
    fun put(context: Context, key: String, value: Any): Boolean {
        return put(getDefaultStore(context), key, value)
    }

    /**
     * 基础类型的获取
     *
     * @param context      context
     * @param key          key
     * @param defaultValue defaultValue
     * @return the save value or defaultValue for none
     */
    operator fun <T> get(context: Context, key: String, @NotNull defaultValue: T): T {
        return get(getDefaultStore(context), key, defaultValue)
    }

    /**
     * 非泛型对象的保存
     *
     * @param context context
     * @param key     key
     * @param object  Non-generic object, object's fields also couldn't be generic
     * @return is operation success
     */
    fun putObject(context: Context, key: String, `object`: Any): Boolean {
        return putObject(getDefaultStore(context), key, `object`)
    }

    /**
     * 非泛型对象的获取
     *
     * @param context context
     * @param key     key
     * @param tClass  Non-generic object class
     * @param <T>     object type
     * @return the save object or null for none
    </T> */
    fun <T> getObject(context: Context, key: String, tClass: Class<T>): T? {
        return getObject(getDefaultStore(context), key, tClass)
    }

    /**
     * 集合的保存
     *
     * @param context context
     * @param key     key
     * @param list    list object
     * @return is operation success
     */
    fun putList(context: Context, key: String, list: List<*>): Boolean {
        return putList(getDefaultStore(context), key, list)
    }

    /**
     * 集合的获取
     *
     * @param context context
     * @param key     key
     * @param tClass  list object class
     * @param <T>     object type
     * @return the save list or null for none
    </T> */
    fun <T> getList(context: Context, key: String, tClass: Class<Array<T>>): List<T>? {
        return getList(getDefaultStore(context), key, tClass)
    }

    /**
     * 判断是否包含某个key
     *
     * @param context context
     * @param key     key
     * @return is contains the key
     */
    fun contains(context: Context, key: String): Boolean {
        return contains(getDefaultStore(context), key)
    }

    /**
     * 移除key对应的value
     *
     * @param context context
     * @param key     key
     * @return is operation success
     */
    fun remove(context: Context, key: String): Boolean {
        return remove(getDefaultStore(context), key)
    }

    /**
     * 清空所有数据
     *
     * @param context context
     * @return is operation success
     */
    fun clear(context: Context): Boolean {
        return clear(getDefaultStore(context))
    }

    /**
     * 使用特定分组名的MMKV封装
     */
    class NamedTP(context: Context, val name: String) {
        private val adapter: IStore = MMKVStore.getImpl(context, name)

        /**
         * 使用特定分组名，基础类型的保存
         *
         * @param key   key
         * @param value value
         * @return is operation success
         */
        fun put(key: String, value: Any): Boolean {
            return put(adapter, key, value)
        }

        /**
         * 使用特定分组名，基础类型的获取
         *
         * @param key          key
         * @param defaultValue defaultValue
         * @return the save value or defaultValue for none
         */
        operator fun <T> get(key: String, defaultValue: T): T {
            return get(adapter, key, defaultValue)
        }

        /**
         * 使用特定分组名，非泛型对象的保存
         *
         * @param key    key
         * @param object Non-generic object, object's fields also couldn't be generic
         * @return is operation success
         */
        fun putObject(key: String, `object`: Any): Boolean {
            return putObject(adapter, key, `object`)
        }

        /**
         * 使用特定分组名，非泛型对象的获取
         *
         * @param key    key
         * @param tClass Non-generic object class
         * @param <T>    object type
         * @return the save object or null for none
        </T> */
        fun <T> getObject(key: String, tClass: Class<T>): T? {
            return getObject(adapter, key, tClass)
        }

        /**
         * 使用特定分组名，集合的保存
         *
         * @param key  key
         * @param list list object
         * @return is operation success
         */
        fun putList(key: String, list: List<*>): Boolean {
            return putList(adapter, key, list)
        }

        /**
         * 使用特定分组名，集合的获取
         *
         * @param key    key
         * @param tClass list object class
         * @param <T>    object type
         * @return the save list or null for none
        </T> */
        fun <T> getList(key: String, tClass: Class<Array<T>>): List<T>? {
            return getList(adapter, key, tClass)
        }

        /**
         * 使用特定分组名，判断是否包含某个key
         *
         * @param key key
         * @return is contains the key
         */
        operator fun contains(key: String): Boolean {
            return contains(adapter, key)
        }

        /**
         * 使用特定分组名，移除key对应的value
         *
         * @param key key
         * @return is operation success
         */
        fun remove(key: String): Boolean {
            return remove(adapter, key)
        }

        /**
         * 使用特定分组名，清空所有数据
         *
         * @return is operation success
         */
        fun clear(): Boolean {
            return clear(adapter)
        }

    }

    // 私有方法
    private fun put(adapter: IStore, key: String, value: Any): Boolean {
        return adapter.put(key, value)
    }

    private operator fun <T> get(adapter: IStore, key: String, @NotNull defaultValue: T): T {
        return adapter[key, defaultValue]
    }

    private fun putObject(adapter: IStore, key: String, `object`: Any): Boolean {
        return adapter.putObject(key, `object`)
    }

    private fun <T> getObject(adapter: IStore, key: String, tClass: Class<T>): T? {
        return adapter.getObject(key, tClass)
    }

    private fun putList(adapter: IStore, key: String, list: List<*>): Boolean {
        return adapter.putList(key, list)
    }

    private fun <T> getList(adapter: IStore, key: String, tClass: Class<Array<T>>): List<T>? {
        return adapter.getList(key, tClass)
    }

    private fun contains(adapter: IStore, key: String): Boolean {
        return adapter.contains(key)
    }

    private fun remove(adapter: IStore, key: String): Boolean {
        return adapter.remove(key)
    }

    private fun clear(adapter: IStore): Boolean {
        return adapter.clear()
    }

    private fun getDefaultStore(context: Context): IStore {
        if (adapter == null) {
            synchronized(TPUtils::class.java) {
                if (adapter == null) {
                    adapter = MMKVStore.getImpl(context, DEFAULT_GROUP_NAME)
                }
            }
        }
        return adapter!!
    }

    fun getSpecificStore(context: Context, name: String): NamedTP {
        if (mSpecificNamedTp != null && mSpecificNamedTp!!.name == name) {
            return mSpecificNamedTp!!
        }
        synchronized(TPUtils::class.java) {
            if (mSpecificNamedTp != null && mSpecificNamedTp!!.name == name) {
                return mSpecificNamedTp!!
            }
            var namedTP = cacheNamedTps[name]
            if (namedTP != null) {
                mSpecificNamedTp = namedTP
                return namedTP
            }
            namedTP = NamedTP(context, name)
            cacheNamedTps[name] = namedTP
            mSpecificNamedTp = namedTP
            return namedTP
        }
    }
}